;start
[org 0x7c00]

; 设置屏幕位文本模式 清除屏幕
mov ax,3
int 0x10

;init org
mov ax, 0
mov ds, ax
mov es, ax 
mov ss, ax
mov sp, 0x7c00



mov si,booting   ;si 变址寄存器
call print       ;调用print 函数

mov edi,0x1000; 读取的目标的内存  也就将指针移动到要操作的位
mov ecx,2;      起始地址            
mov bl,4;       扇区数量  bl 8位寄存器

call read_disk;

cmp word [0x1000],0x55aa ;用来比较内核加载器是否正确
jnz error

jmp 0:0x1002

; mov edi,0x1000; 读取的目标的内存  也就将指针移动到要操作的位
; mov ecx,2;      起始扇区            
; mov bl,1;       扇区数量  bl 8位寄存器

; call Write_disk;

; 阻塞
jmp $

read_disk:

    ;读出扇区

    ;设置读写扇区的数量
    mov dx,0x1f2
    mov al,bl
    out dx,al ;out 是输出指令 AL的值（即BL的值）将被写入到端口地址0x1f2。
    
    inc dx; 0x1f3 inc 是 自加指令
    mov al,cl ;起始扇区的低八位
    out dx,al 
    
    inc dx; 0x1f4 
    shr ecx,8 ;寄存器ECX的值逻辑右移8位 ,将低8位清空
    mov al,cl ;起始扇区的中八位
    out dx,al 

    inc dx; 0x1f5 
    shr ecx,8 ;寄存器ECX的值逻辑右移8位，将中低8位清空
    mov al,cl ;起始扇区的高八位
    out dx,al 
    
    inc dx; 0x1f6 
    shr ecx,8 ;寄存器ECX的值逻辑右移8位，将高低8位清空
    and cl,0b1111; 经cl寄存器里边的高四位内容

    mov al,0b1110_0000;
    or al,cl
    out dx,al ;主盘，- LBA 模式

    inc dx; 0x1f7
    mov al,0x20
    out dx,al

    xor ecx,ecx;
    mov cl,bl; 得到读写硬盘的数量

    .read:
        push cx;保存CX
        call .waits;等待数据准备完成
        call .reads;读取一个扇区
        pop cx; 恢复cx
        loop .read

    ret

    .waits:
        mov dx,0x1f7
            .check:
                in al,dx
                jmp $+2 ; nop 直接跳转到下一行
                jmp $+2 ; 一点点延时
                jmp $+2
                and al, 0b1000_1000
                cmp al, 0b0000_1000
                jnz .check
    ret

    .reads:
        mov dx,0x1f0
        mov cx,256;
        .readw:
                in ax,dx
                jmp $+2 ; nop 直接跳转到下一行
                jmp $+2 ; 一点点延时
                jmp $+2
                mov [edi],ax
                add edi,2
            loop .readw
    ret

Write_disk:

    ;写入扇区

    ;设置读写扇区的数量
    mov dx,0x1f2
    mov al,bl
    out dx,al ;out 是输出指令 AL的值（即BL的值）将被写入到端口地址0x1f2。
    
    inc dx; 0x1f3 inc 是 自加指令
    mov al,cl ;起始扇区的低八位
    out dx,al 
    
    inc dx; 0x1f4 
    shr ecx,8 ;寄存器ECX的值逻辑右移8位 ,将低8位清空
    mov al,cl ;起始扇区的中八位
    out dx,al 

    inc dx; 0x1f5 
    shr ecx,8 ;寄存器ECX的值逻辑右移8位，将中低8位清空
    mov al,cl ;起始扇区的高八位
    out dx,al 
    
    inc dx; 0x1f6 
    shr ecx,8 ;寄存器ECX的值逻辑右移8位，将高低8位清空
    and cl,0b1111; 经cl寄存器里边的高四位内容

    mov al,0b1110_0000;
    or al,cl
    out dx,al ;主盘，- LBA 模式

    inc dx; 0x1f7  0x1f7硬盘状态
    mov al,0x30;设置为写入模式
    out dx,al

    xor ecx,ecx;
    mov cl,bl; 得到读写硬盘的数量

    .Write:
        push cx;保存CX
        call .Writes;写一个扇区
        call .Waits;等待硬盘繁忙结束
        pop cx; 恢复
        loop .Write

    ret

    .Waits:
        mov dx,0x1f7
            .check:
                in al,dx
                jmp $+2 ; nop 直接跳转到下一行
                jmp $+2 ; 一点点延时
                jmp $+2
                and al, 0b1000_0000
                cmp al, 0b0000_0000
                jnz .check
    ret

    .Writes:
        mov dx,0x1f0
        mov cx,256;写入一个字节512
        .Writew:
                mov ax,[edi];将目标寄存器的地址给ax
                out dx,ax;将AX的值给dx
                jmp $+2 ; nop 直接跳转到下一行
                jmp $+2 ; 一点点延时
                jmp $+2
                add edi,2
            loop .Writew
    ret

print:
    mov ah,0x0e ;将AH寄存器设置为0x0e，这是系统中断10的入口地址，用于将字符输出到屏幕。
;.next 将对应的字符以此打印
.next:          ;标记下一条指令的位置。
    mov al,[si] ;将当前的si 寄存器里的值移给al寄存器
    cmp al,0    ;将al 里的值与0作比较
    jz .done    ;如果为0 则跳到.done 处
    int 0x10    ;调用中断0x10，用于将AL寄存器中的字符输出到屏幕。
    inc si      ;如果上一条指令执行后没有产生进位（即上一个字符的输出没有出现错误），则将SI指针增加1，指向下一个字符的内存单元。
    jmp .next   ;跳转到.next标记处的指令，重复执行上述过程，直到遇到字符串结束标记。
.done:
    ret         ;返回调用程序，结束程序的执行。

booting:
    db "Booting Onix...",10,13,0; \n\r ，这里的10 ，13 ，0 对应的是ASCII 表中的符号
error:
    mov si,.msg
    call print
    hlt;让CPU停止
    jmp $
    .msg db "Booting ERROR !!!",10,13,0



;引导扇区为 512 bit 出最后两个字节一位其余为为 0 

;填充为 0 
times 510-($-$$) db 0 
; 主引导扇区的最后两个字节必须是 0X55 ,0Xaa
;dw 0xaa55
db 0x55,0xaa
